﻿package com.cilico.single.components;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Stack;
import java.util.Vector;

import android.graphics.Bitmap;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.cilico.single.ConfigManager;
import com.cilico.single.Mid;
import com.cilico.single.utils.Utils;
import com.cilico.single.view.BaseView;
import com.cilico.single.view.FormAction;
import com.cilico.single.view.FormLayout;
import com.cilico.single.view.SegmentLinearLayout;

public class ParseHtml {

	final class LayoutState {
		boolean isBold_;
		boolean isItalic_;
		boolean isLink_ = false;
		int olNum_ = -1; // 0 menas UL, other means OL.
		boolean isTable_ = false; // Table variables
		boolean isForm_ = false;
		String actionUrl_;
		int color_;
		int prevColor;
		boolean hasBackgroundColor_;
		int backgroundColor_;
		int alignment_; // BOTTOM | TOP | MIDDLE | LEFT | RIGHT | CENTER
		String linkTarget_;
		String tag_; // the text we add to the front fo the item.
		boolean isFirstTag_;

		/** This is for hidden div */
		String id_;
		boolean isHidden_;
		FormAction faction_;

		// Default font style
		int fontFace_;
		int fontStyle_;
		int fontSize_;
		Paint font_;

		public LayoutState() {
			setDefaultLayoutState();
		}

		public void setDefaultLayoutState() {
			font_ = new Paint();
			font_.setTextSize(Utils.getScaledValue(ConfigManager.SIZE_MEDIUM));
			font_.setTypeface(Typeface.DEFAULT);
			isBold_ = false;
			isItalic_ = false;
			hasBackgroundColor_ = false;
			// alignment_ = Graphics.BOTTOM;
			color_ = Utils.BLACK;
			prevColor = Utils.BLACK;
		}
	}

	BaseView parent_;
	// Store image items.
	Vector<ImageItem> items_;
	// Store images.
	Vector<Bitmap> images_;
	// Store images url
	Vector<String> imagesUrl_;
	// use for creat form action.

	String textInForm_;

	private Mid mid_;
	LayoutState ls_;
	Component view_;
//	private HtmlText htmlText_;

	/* fields for Table */
	Table table_;
	Table.Cell currentCell_;
	int currentRow_ = -1;
	int currentCol_ = -1;

	// to store the new style instances.
	Stack<CssStyle> styleStack_;
	// to store all the styles.
	HashMap<String, CssStyle> nodeStyles_;// 标签样式集合
	HashMap<String, CssStyle> classStyles_;// 类样式集合

	// stack to restore the <DIV>.
	private Stack<Div> divStack_;

	// form节点控件，如果xml中存在form节点，则改变量启用，在该节点内的所有域全部加至该控件
	FormLayout formLayout_;

	/* Data of parse result */
	ArrayList<Component> cmps_;
	String hidden_;
	
	Vector<ImageView> itemRemote_;
	Vector<Bitmap> imageRemote_;
	Vector<String> imageUrlRemote_;
	// use for creat form action.
	
	/**
	 * @param parent
	 * @param mid
	 */
	public ParseHtml(BaseView parent, Mid mid) {
		parent_ = parent;
		mid_ = mid;
		ls_ = new LayoutState();

		styleStack_ = new Stack<CssStyle>();

		divStack_ = new Stack<Div>();

		formLayout_ = null;

		cmps_ = new ArrayList<Component>();
	}

	// void addLsItemAndroid(BaseView activity) throws Exception {
	// if (view_ == null)
	// return;
	// activity.appendAtFixP(view_);
	// if (ls_.isForm_ && ls_.faction_ != null) {
	// ls_.faction_.addItem(view_);
	// }
	// view_ = null;
	// }

	void addLsItem(BaseView activity) throws Exception {
		if (textInForm_ != null) {
			// text has NOT been appended.
			createNewItem(activity, textInForm_, false);
			textInForm_ = null;
		}
		if (view_ == null) {
			return;
		}
		appendView(activity);
		if (ls_.isForm_ && ls_.faction_ != null && !(view_ instanceof Wrap)) {
			ls_.faction_.addItem(view_);
		}

		view_ = null;
	}

	/**
	 * @param activity
	 * @param view
	 */
	private void appendView(BaseView activity) {
		if (ls_.isHidden_ || view_ == null) {
			return;
		}
		// apply CSS style.
		applyCssOnComponent(view_, peekStyle(), nodeStyles_);
		if (ls_.isTable_) {
			// add the View to Table if it is in <Table>.
			currentCell_.add(view_);
			if(view_ instanceof mTextField){
				table_.hasTextField_ = true;
			}
		} else {
			Div currentDiv = null;
			currentDiv = peekDiv();
			if (currentDiv == null) {
				// 如果formLayout_不为空，表示正存在于form节点内，此时应把控件加入到FormLayout管理器，反之则直接加到界面管理器
				if (null != formLayout_ && ls_.isForm_) {
					((Component) view_).setInTable(ls_.isTable_);
					formLayout_.addChild((Component) view_);
				} else {
					cmps_.add((Component) view_);
				}
			} else {
				currentDiv.addChild((Component) view_);
			}
		}
		activity.vWidgetArray_.add(view_);
	}

	/**
	 * @param div
	 * @param cssStyle
	 */
	void addNewDiv(Div div) {
		if (div == null || parent_ == null) {
			return;
		}
		if (div.cssStyle_ != null && div.cssStyle_.display_ != null && div.cssStyle_.display_.equals("none")) {
			parent_.appendInvisible(div);
			mid_.appendCacheDiv(div);// 保存隐藏div到缓存列表中
			div.removeAllViews();
			Div parentDiv = peekDiv();
			if (parentDiv != null) {
				parentDiv.removeChild(div);
			}
		} else if (isDivStackEmpty()) {
			if (formLayout_ == null) {
				cmps_.add(div);
			} else {
				formLayout_.addChild(div);
			}
		}
	}

	/**
	 * Create a new item, initialize it for text.
	 */
	void createNewItem(final BaseView activity, String text, boolean isForceNoTrim) throws Exception {
		boolean isTrimHead = true;
		if (ls_.tag_ != null) {
			String tag = ls_.tag_;
			if (!ls_.isFirstTag_) {
				StringBuffer blanks = new StringBuffer();
				for (int i = 0; i < tag.length(); i++) {
					blanks.append(" ");
				}
				tag = blanks.toString();
				isTrimHead = false;
			}
			text = (text != null) ? tag + text : tag;

			ls_.isFirstTag_ = false;
		}
		if (text == null)
			return;
		if (isForceNoTrim)
			isTrimHead = false;
		mHtmlText htmlText = null;

		int color = ls_.color_;
		int bColor = 0;
		try {
			CssStyle currStyle = peekStyle();
			// set the text color.
			if (currStyle.fgColor_ != 0) {
				color = currStyle.fgColor_;
			}
			// set the backGround color
			if (currStyle.bgColor_ != 0) {
				bColor = currStyle.bgColor_;
			}
			// set the font size.
			if (currStyle.fontSize_ > 0) {
				ls_.font_.setTextSize(currStyle.fontSize_);
			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
		}

		if (view_ == null) {
			htmlText = new mHtmlText(activity, null, false, ls_.font_);
		} else {
			try {
				htmlText = (mHtmlText) view_;
			} catch (Exception ex) {
				htmlText = new mHtmlText(activity, null, false, ls_.font_);
			}
		}

		if (ls_.hasBackgroundColor_) {
			htmlText.setBackgroundColor(ls_.backgroundColor_);
		}
		if (ls_.isLink_) {// && !ls.isTable_) {
			htmlText.setToLink(ls_.linkTarget_);
			htmlText.isHyperLink_ = true;
			// applyPseudoCssOnLabel(lpHtmlText, nodeStyles_.get("a:active"));
			if (null != nodeStyles_)
				htmlText.pseudoStyle_ = nodeStyles_.get("a:active");
		} else {
			htmlText.setFocusable(false);
		}

		if (ls_.isTable_) {
			// 初始化控件的界面输出参数
			htmlText.width_ = (int) (htmlText.font_.measureText(text) + 4);
			int w = parent_.preferredItemTextWidth();
			// we set one cell's maxWidth not bigger than the screen width. And
			// we should init maxWidth_ before setText().
			if (htmlText.width_ > w)
				htmlText.width_ = w;
			htmlText.addText(text, ls_.font_, color, bColor, false, ls_.isLink_, ls_.linkTarget_, isTrimHead, true);
			htmlText.width_ += Table.OFFSET;

			htmlText.setLayoutParams(new LinearLayout.LayoutParams(htmlText.width_, htmlText.height_));
		} else {
			htmlText.addText(text, ls_.font_, color, bColor, false, ls_.isLink_, ls_.linkTarget_, isTrimHead, true);
			htmlText.setLayoutParams(new LinearLayout.LayoutParams(htmlText.width_, htmlText.height_));
		}

		view_ = htmlText;

	}

	/**
	 * Layout an image Element. Looks for the SRC and ALIGN tags
	 * 
	 * @param alt
	 *            TODO
	 * @param elt
	 *            A IMAGE element
	 * @param ls
	 *            the current layout state
	 */
	public void layoutImageElement(final boolean isInForm, final String src, String link, String align, String alt, BaseView bv, boolean isloading) throws Exception {
		if (src == null) {
			return;
		}
		if (align == null) {
			align = "BOTTOM";
		}
		if (isInForm) {
			// img节点在form节点内

		} else {
			// 判断条件为非，表示该节点不在form节点之内
			if (src.equalsIgnoreCase("ewp_app_logo")) {
				Utils.hiddenTitleBar_ = true;
				// img节点属性为ewp_app_logo时，表示此时取客户端本地图片
				Bitmap bm = Utils.getBitmapFromDrawable(src, bv);
				if (null != bm) {
					ImageItem imItem = new ImageItem(bv, bm);
					bv.tabBar_.addContentChild(imItem);
				}
				// 已经读取到本地图片，可返回。
				return;
			} else {
				// 指定源为非本地图片
			}
		}
		CssStyle cs = peekStyle();
		Bitmap image = Utils.createImgWaitLoad(mid_, alt, 0x88888888, cs.width_, cs.height_);
		// Build the new image item.
		ImageItem item = new ImageItem(bv, image);
		item.link_ = link;
		item.setCssStyle(cs);
		if (ls_.isLink_)
			item.setUrl(ls_.linkTarget_);
		else
			item.focusable_ = false;
		String url = src;
		if (!isloading) {
			// make an absolute SRC URL to get the image
			if (images_ == null)
				images_ = new Vector<Bitmap>();
			if (imagesUrl_ == null)
				imagesUrl_ = new Vector<String>();
			// add this image link in the list of image url.
			imagesUrl_.addElement(url);
			if (items_ == null)
				items_ = new Vector<ImageItem>();
			items_.addElement(item);
		} else {
			if (imageRemote_ == null)
				imageRemote_ = new Vector<Bitmap>();
			if (imageUrlRemote_ == null)
				imageUrlRemote_ = new Vector<String>();
			// add this image link in the list of image url.
			imageUrlRemote_.addElement(url);
			if (itemRemote_ == null)
				itemRemote_ = new Vector<ImageView>();
			itemRemote_.addElement(item);
		}
		
		if (ls_.isTable_) {
			// Get currentCell_.
			Table.Cell cell = currentCell_;
			cell.add(item);
			item.width_ += Table.OFFSET;
			// cell.width = Math.max(item.width_, cell.width);
			// cell.height += item.height_;
		} else {
			item.setPadding(0, 0, 10, 10);
			bv.append(item);
			bv.appendAtFixP(item);
		}
	}
	
	public void downloadImageFromRemote() {
		WaitDialog dlg = BaseView.mid_.waitDialog_;

		dlg.addBgTask(new WaitDialog.Task(2) {
			public void run(WaitDialog dlg) {
				if (imageUrlRemote_ != null) {
					for (int i = 0; i < imageUrlRemote_.size(); i++) {
						try {
							// download image
							BaseView.mid_.downloadImageRemote((String) imageUrlRemote_.elementAt(i), i,imageRemote_);
							changeImageRemoteAfterLoad(i);
						} catch (Exception ex) {
							Utils.printOutToConsole("LPParseHtml-downloadImageFromServer-ex:" + ex.toString());
						}
					}
				}
			}

			public void onSuccess(WaitDialog dlg) {
				parent_.runOnUiThread(new Runnable() {
					public void run() {
						parent_.tabBar_.getContentLayout().invalidate();
					}
				});
			}

		});
	}

	public void downloadImageFromServer() {
		WaitDialog dlg = BaseView.mid_.waitDialog_;
		dlg.addBgTask(new WaitDialog.Task(2) {
			public void run(WaitDialog dlg) {
				for (int i = 0; i < imagesUrl_.size(); i++) {
					try {
						// download image
						BaseView.mid_.downloadImage((String) imagesUrl_.elementAt(i), i, parent_.preferredImageWidth(), parent_.preferredImageHeight(), images_);
					} catch (Exception ex) {
						Utils.printOutToConsole("LPParseHtml-downloadImageFromServer-ex:" + ex.toString());
					}
				}
			}

			public void onSuccess(WaitDialog dlg) {
				changeImagePositionAfterLoad();
				parent_.runOnUiThread(new Runnable() {
					public void run() {
						parent_.tabBar_.getContentLayout().invalidate();
					}
				});
			}
		});
	}

	/**
	 * If the size of the image downloaded is less than the size predefined, we should reset the ypos of the line succeed.
	 * 
	 */
	private void changeImagePositionAfterLoad() {
		for (int j = 0; j < images_.size(); j++) {
			ImageItem item = (ImageItem) items_.elementAt(j);
			Bitmap map = null;
			if (images_.elementAt(j) != null) {
				 map = Bitmap.createScaledBitmap((Bitmap) images_.elementAt(j), item.width_, item.height_, true);
			} else { 
				 map = Utils.createImgWaitLoad(mid_, "暂无图片", 0xffefe9e8, item.width_ + 3, item.height_ + 1);
			}
			item.setImage(map);
		}

	}

	private void changeImageRemoteAfterLoad(final int index) {
		if (itemRemote_.elementAt(index) instanceof ImageItem){
			ImageItem item = (ImageItem) itemRemote_.elementAt(index);
			if (null != (Bitmap) imageRemote_.elementAt(index)) {
				item.setImage((Bitmap) imageRemote_.elementAt(index));
			} else {
				item.setImage(Utils.createImgWaitLoad(mid_, "暂无图片", 0xffefe9e8, item.width_ + 3, item.height_ + 1));
			}
		}else if (itemRemote_.elementAt(index) instanceof ImageView && itemRemote_.elementAt(index).getId()/10 == 123){
			ImageView item = (ImageView) itemRemote_.elementAt(index);
			if (null != (Bitmap) imageRemote_.elementAt(index)) {
				item.setImageBitmap((Bitmap) imageRemote_.elementAt(index));
			}
		}
		
	}
	
	/**
	 * create a new style for the element named localName with the classStr, and push it into the stack if necessary.
	 * 
	 * @param localName
	 * @param classStr
	 */
	final void pushStyle(final String localName, final String classStr) throws Exception {
		CssStyle parentStyle = null;
		if (styleStack_ != null) {
			try {
				parentStyle = styleStack_.peek();
			} catch (Exception e) {
			}
		}
		CssStyle elemStyle = null;
		if (nodeStyles_ != null) {
			CssStyle temp = nodeStyles_.get(localName);
			if (!localName.equals("select")) {
				elemStyle = nodeStyles_.get(localName);
			} else if (temp != null) {
				elemStyle = new CssStyle();
				elemStyle.top_ = temp.top_;
				elemStyle.bottom_ = temp.bottom_;
				elemStyle.left_ = temp.left_;
				elemStyle.right_ = temp.right_;
				elemStyle.textAlign_ = temp.textAlign_;
			}
		}

		CssStyle neoStyle = null;
		/* unite the element style to the parent style. */
		if (elemStyle != null) {
			neoStyle = CssStyle.uniteStyle(parentStyle, elemStyle);
		}
		/* unite the class style to the parent style. */
		String[] classArr = Utils.string2Array(classStr, ",");
		if (classArr != null && classStyles_ != null) {
			for (int i = 0; i < classArr.length; i++) {
				CssStyle classStyle = classStyles_.get(classArr[i]);
				if (classStyle != null) {
					neoStyle = CssStyle.uniteStyle(neoStyle, classStyle);
				}
			}
		}
		/* check if a new style has been created. */
		if (neoStyle == null) {
			neoStyle = CssStyle.copy(parentStyle);
		}
		styleStack_.push(neoStyle);
	}

	/**
	 * @return
	 */
	final CssStyle peekStyle() {
		CssStyle pkStyle = null;
		// peek the current style if it's there.
		try {
			pkStyle = styleStack_.peek();
		} catch (Exception e) {
			pkStyle = null;
		}
		return pkStyle;
	}

	/**
	 * @param ll
	 */
	final void pushDiv(Div ll) {
		try {
			divStack_.push(ll);
		} catch (Exception e) {
			// TODO Auto-generated catch block
		}
	}

	/**
	 * @return
	 */
	final Div peekDiv() {
		Div div = null;
		try {
			div = divStack_.peek();
		} catch (Exception e) {
			// TODO Auto-generated catch block
		}
		return div;
	}

	/**
	 * @return
	 */
	final Div popDiv() {
		Div div = null;
		try {
			div = divStack_.pop();
		} catch (Exception e) {
			// TODO Auto-generated catch block
		}
		return div;
	}

	/**
	 * @return
	 */
	final boolean isDivStackEmpty() {
		try {
			return divStack_.isEmpty();
		} catch (Exception e) {
			return true;
		}
	}

	/**
	 * @param obj
	 *            component to use the style
	 * @param style
	 */
	static final void applyCssOnComponent(final Object obj, final CssStyle style,
			final HashMap<String, CssStyle> nodeStyles) {
		try {
			// if (obj instanceof ViewGroup) {
			// applyCssOnLayout((ViewGroup) obj, style);
			// } else if (obj instanceof Cell) {
			// applyCssOnTable((Cell) obj, style);
			// } else if (obj instanceof TextView) {
			// applyCssOnTextView((TextView) obj, style);
			// applyPseudoCss((TextView) obj, nodeStyles);
			// }
			((Component) obj).setCssStyle(style);
			if (obj instanceof Label) {
				CssStyle pseudoStyle = nodeStyles.get("a:active");
				((Label) obj).pseudoStyle_ = pseudoStyle;
			} else if (obj instanceof mButton) {
				CssStyle pseudoStyle = nodeStyles.get("button:active");
				((mButton) obj).pseudoStyle_ = pseudoStyle;
			}
		} catch (Exception e) {
			Utils.printException(e);
		}
	}

	public Object getSelectRadio(BaseView activity, Radio temp) {
		String groupName = temp.groupName_;
		synchronized (BaseView.UI_LOCK) {
			int size = activity.vWidgetArray_.size();
			for (int i = 0; i < size; i++) {
				Object o = activity.vWidgetArray_.elementAt(i);
				if (o instanceof Wrap)
					continue;
				if (o instanceof Radio) {
					Radio r = (Radio) o;
					if (r.groupName_ != null && r.groupName_.equals(groupName) && r.isChecked())
						return r;
				} else if (o instanceof SegmentLinearLayout) {
					SegmentLinearLayout sll = (SegmentLinearLayout) o;
					int sizeTemp = sll.getChildCount();
					Utils.printOutToConsole("sizeTemp == " + sizeTemp);
					for (int j = 0; j < sizeTemp; j++) {
						Radio radio = (Radio) sll.getChildAt(j);
						/**
						 * 如果一个界面存在多个segment控件组且每个控件组都有不同的组名则使用该判断条件 if (radio.groupName_ != null &&
						 * radio.groupName_.equals(groupName) && radio.isChecked())
						 */
						if (radio.isChecked() || radio.isChecked_)
							return radio;
					}
				}
			}
		}
		return null;
	}

	public void clearResource() {

		if (items_ != null) {
			items_.removeAllElements();
			items_ = null;
		}
		
		if (itemRemote_ != null) {
			itemRemote_.removeAllElements();
			itemRemote_ = null;
		}

		if (images_ != null) {
			images_.removeAllElements();
			images_ = null;
		}

		if (imageRemote_ != null) {
			imageRemote_.removeAllElements();
			imageRemote_ = null;
		}
		
		if (imagesUrl_ != null) {
			imagesUrl_.removeAllElements();
			imagesUrl_ = null;
		}

		if (imageUrlRemote_ != null) {
			imageUrlRemote_.removeAllElements();
			imageUrlRemote_ = null;
		}


		if (view_ != null) {
			view_ = null;
		}

	}

}
